package dk.ucn.datamatiker.saveme;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources.NotFoundException;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.NotificationCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.RemoteViews;
import android.widget.Toast;

public class SaveMeMainActivity extends Activity {
	private Location mLocation;
	private LocationManager mLocationManager;
	private TelephonyManager telephonyManager;
	private ImageButton mainButton;
	private Address addr;
	private Handler updateTaskHandler;
	private Runnable updateTask;
	private Runnable networkTask;
	private int result = -1, stateResult = -1;
	private String phoneNumber;
	private EditText etStreetName, etStreetNumber, etCity;
	private ImageButton cancelButton;
	private SharedPreferences settings;
	private static boolean isStatus1 = false, isStatus2 = false, isStatus3 = false;
	private static final int UPDATE_TIME = 30000;
	private static final String URL_TAXI_STATUS = "GetMyTaxiStatus/";
	private static final String URL_SEND_LOCATION = "SendMyLocationWithPhoneNr/";
	private static final String URL_CANCEL = "http://balder.ucn.dk/dm77_gr2/SaveMe.svc//CancelTaxiRequestFromPhone/";
	public static final String PHONE_NUMBER = "phoneNumber";
	private static final int UNIQUE_ID = 100;
	private static final String REQUEST_ID = "requestID";
	private String[] estTimePlateNr = null;
	private NotificationManager notificationManager;
	private TaxiDetailsFetcher taxiDetailFetcher;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_save_me_main);
		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		mLocation = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
		telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		settings = getSharedPreferences(SettingsActivity.PREFS_NAME, MODE_PRIVATE);

		etStreetName = (EditText) findViewById(R.id.etStreet);
		etStreetName.setText(phoneNumber);
		etStreetNumber = (EditText) findViewById(R.id.etNumber);
		etCity = (EditText) findViewById(R.id.etCity);
		mainButton = (ImageButton) findViewById(R.id.ibSend);
		cancelButton = (ImageButton) findViewById(R.id.cancelButton);
		updateTaskHandler = new Handler();

		cancelButton.setOnClickListener(new OnClickListener() {	
			public void onClick(View v) {
				Toast.makeText(getApplicationContext(), R.string.cancel_button_message, Toast.LENGTH_LONG).show();
			}
		});
		
		cancelButton.setOnLongClickListener(new OnLongClickListener() {
			public boolean onLongClick(View v) {
				try {
					if (isNetworkAvailable()) {
						Thread t = new Thread(new Runnable() {
							public void run() {
								updateTaskHandler.removeCallbacks(updateTask);
								cancelTaxiOrder(result);
								setStatusesToFalse();
							}
						});
						t.start();
						t.join();
						Toast.makeText(getApplicationContext(), R.string.taxi_cancel_message, Toast.LENGTH_LONG).show();
						showNotification(v.getContext(), getResources().getString(R.string.taxi_cancel_message));
						stateResult = -1;
						mainButtonVisible();
					}
				} catch (InterruptedException interruptedException) {
					Log.e("SaveMeMainActivity", "cancelButton", interruptedException);
				}
				return true;
			}
		});

		mainButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (addressIsProvided()) {
					if (isNetworkAvailable()) {
						cancelButtonVisible();
						orderTaxi();
						Toast.makeText(getApplicationContext(), R.string.taxi_ordered, Toast.LENGTH_LONG).show();
					} else {
						Toast.makeText(getApplicationContext(),R.string.network_problem, Toast.LENGTH_LONG).show();
					}
				}
				else {
					Toast.makeText(getApplicationContext(), R.string.address_not_provided, Toast.LENGTH_LONG).show();
				}
			}
		});
	}

	protected void onResume() {
		super.onResume();
		if(isStatus1 || isStatus2 || isStatus3){
			result = settings.getInt(REQUEST_ID, -1);
			cancelButtonVisible();
		}else{
			mainButtonVisible();
		}
		networkTask = new Runnable() {
			public void run() {
				if (isNetworkAvailable()) {
					mLocationManager.requestLocationUpdates(getBestLocationProvider(), 0, 0, locationListener);
					
					addr = getAddress();
					if (addr != null) {
						etStreetName.setText(addr.getThoroughfare());
						etStreetNumber.setText(addr.getFeatureName());
						etCity.setText(addr.getLocality());
					}
					updateTaskHandler.removeCallbacks(networkTask);
				} else {
					Toast.makeText(getApplicationContext(),
							R.string.network_problem, Toast.LENGTH_LONG).show();
					updateTaskHandler.postDelayed(networkTask, UPDATE_TIME);
				}
			}
		};
		updateTaskHandler.post(networkTask);
	}

	protected void onPause() {
		super.onPause();
		// terminating location update to reduce unnecessary consumption of power and bandwidth
		mLocationManager.removeUpdates(locationListener);
		// terminate network callback
		updateTaskHandler.removeCallbacks(networkTask);
	}

	private Address getAddress() {
		List<Address> addresses;
		Address currentAddr = null;
		try {
			if (isNetworkAvailable()) {
				Geocoder mGC = new Geocoder(this, Locale.ENGLISH);
				addresses = mGC.getFromLocation(mLocation.getLatitude(), mLocation.getLongitude(), 1);

				if (addresses != null) {
					currentAddr = addresses.get(0);
				}
			}
		} catch (IOException ioException) {
			Log.e("SaveMeMainActivity", "getAddress()" , ioException);
		}
		return currentAddr;
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.save_me_main, menu);
		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.action_settings:
			launchSettings();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	private void launchSettings() {
		Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);
		if (telephonyManager.getLine1Number() != null) {
			intent.putExtra(PHONE_NUMBER, telephonyManager.getLine1Number());
		}
		startActivity(intent);
	}

	private void cancelTaxiOrder(int orderID) {
		InputStream inputStream = null;
		try {
			URL url = new URL(URL_CANCEL + orderID);
			inputStream = url.openConnection().getInputStream();
		} catch (IOException ioException) {
			Log.e("SaveMeMainActivity", "cancelTaxiOrder()", ioException);
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException ioException2) {
					Log.e("SaveMeMainActivity", "cancelTaxiOrder()", ioException2);
				}
			}
		}
	}

	private boolean addressIsProvided() {
		boolean isProvided = false;
		String street = etStreetName.getText().toString();
		String number = etStreetNumber.getText().toString();
		String city = etCity.getText().toString();

		if (street.length() > 0 && number.length() > 0 && city.length() > 0) {
			isProvided = true;
		}

		return isProvided;
	}

	private void orderTaxi() {
		mainButton.setClickable(false);
		final String url_end;

		if (!settings.getString(PHONE_NUMBER, "").equals("")) {
			url_end = etStreetName.getText().toString() + " " + etStreetNumber.getText().toString() + " " 
					+ etCity.getText().toString() + "-" + settings.getString(PHONE_NUMBER, "");
		} else {
			url_end = etStreetName.getText().toString() + " " + etStreetNumber.getText().toString() + " "
					+ etCity.getText().toString() + "-No_phone_number";
		}

		try {
			if (isNetworkAvailable()) {
				// replacing spaces with underscore in address string
				result = Integer.valueOf(new TaxiRequest().execute((URL_SEND_LOCATION + url_end.replaceAll("\\s", "_"))).get());

				updateTask = new Runnable() {
					public void run() {
						try {
							stateResult = Integer.valueOf(new TaxiRequest().execute(URL_TAXI_STATUS + result).get());
							switch (stateResult) {

							case 1:
								if (!isStatus1) {
									showNotification(getBaseContext(),getResources().getString(R.string.status_1));
									isStatus1 = true;
								}
								updateTaskHandler.postDelayed(updateTask, UPDATE_TIME);
								break;
							case 2:
								if (!isStatus2) {
									taxiDetailFetcher = new TaxiDetailsFetcher(result);
									Thread taxiDetailFetcherThread = new Thread(taxiDetailFetcher);
									taxiDetailFetcherThread.start();
									taxiDetailFetcherThread.join();
									estTimePlateNr = taxiDetailFetcher.getResponse();
									notificationManager.cancel(UNIQUE_ID);
									showNotification(getBaseContext(), buildFullMessageStatus2(estTimePlateNr));
									isStatus2 = true;
								}
								updateTaskHandler.postDelayed(updateTask, UPDATE_TIME);
								break;
							case 3:
								if (!isStatus3) {
									notificationManager.cancel(UNIQUE_ID);
									showNotification(getBaseContext(), buildFullFinalMessageStatus3(estTimePlateNr));
									mainButtonVisible();
									isStatus3 = true;
								}
								updateTaskHandler.removeCallbacks(updateTask);
								break;
							}
						} catch (InterruptedException e) {
							Log.e("SaveMeMainActivity", "orderTaxi()", e);
						} catch (ExecutionException e) {
							Log.e("SaveMeMainActivity", "orderTaxi()", e);
						} catch(NumberFormatException numberFormatException) {
							Log.e("SaveMeMainActivity", "orderTaxi()", numberFormatException);
						} catch(NotFoundException notFoundException) {
							Log.e("SaveMeMainActivity", "orderTaxi()", notFoundException);
						}
					}
				};
				updateTaskHandler.post(updateTask);
			} else {
				Toast.makeText(getApplicationContext(), R.string.network_problem, Toast.LENGTH_LONG).show();
			}
		} catch (InterruptedException e) {
			Log.e("SaveMeMainActivity", "orderTaxi()", e);
		} catch (ExecutionException e) {
			Log.e("SaveMeMainActivity", "orderTaxi()", e);
		}
	}

	private boolean isNetworkAvailable() {
		ConnectivityManager conManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
		NetworkInfo networkInfo = conManager.getActiveNetworkInfo();
		return networkInfo != null && networkInfo.isConnected();
	}

	private String buildFullMessageStatus2(String[] info) {
		return "Taxi will arrive in: " + info[0] + "\nPlate number: " + info[1];
	}

	private String buildFullFinalMessageStatus3(String[] estTimePlateNr) {
		return "The taxi arrived.\nPlate number:  " + estTimePlateNr[1];
	}

	private final LocationListener locationListener = new LocationListener() {

		@Override
		public void onLocationChanged(Location location) {
			mLocation = location;
		}

		@Override
		public void onProviderDisabled(String provider) {
		}

		@Override
		public void onProviderEnabled(String provider) {
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
		}

	};

	private String getBestLocationProvider() {
		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
		return mLocationManager.getBestProvider(criteria, true);
	}

	// build notification
	private void showNotification(Context context, String body) {
		RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification_message_view);
		contentView.setTextViewText(R.id.tvNotification, body);
		contentView.setImageViewResource(R.id.ivTaxi, R.drawable.taxi1);
		
		NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
				.setContentTitle(getResources().getString(R.string.taxi_message))
				.setContent(contentView).setContentText(body)
				.setSmallIcon(R.drawable.taxi1)
				.setDefaults(Notification.DEFAULT_SOUND);
		
		if(android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.GINGERBREAD_MR1){
			PendingIntent pIntent = PendingIntent.getActivity(context, 0, new Intent(),0 );
			builder.setContentIntent(pIntent);
		}
		notificationManager.notify(UNIQUE_ID, builder.build());
	}

	private void setStatusesToFalse() {
		isStatus1 = false;
		isStatus2 = false;
		isStatus3 = false;
	}
	
	private void mainButtonVisible() {
		cancelButton.setVisibility(View.GONE);
		mainButton.setVisibility(View.VISIBLE);
	}
	
	private void cancelButtonVisible() {
		mainButton.setVisibility(View.GONE);
		cancelButton.setVisibility(View.VISIBLE);
	}

	public void onStop() {
		super.onStop();
		SharedPreferences.Editor editor = settings.edit();
		editor.putInt(REQUEST_ID, result);
		editor.commit();
	}
}